﻿
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace DeepHash
{
    internal class Utility
    {
        // Taken from http://www.nathanm.com/csharp-converting-hexadecimal-string-tofrom-byte-array-fast/
        // Thanks to Nathan Moinvaziri.
        internal static string ByteArrayToHexString(byte[] Bytes)
        {
            StringBuilder Result = new StringBuilder();
            string HexAlphabet = "0123456789abcdef";

            foreach (byte B in Bytes)
            {
                Result.Append(HexAlphabet[(int)(B >> 4)]);
                Result.Append(HexAlphabet[(int)(B & 0xF)]);
            }

            return Result.ToString();
        }

        // Taken from http://www.nathanm.com/csharp-converting-hexadecimal-string-tofrom-byte-array-fast/
        // Thanks to Nathan Moinvaziri.
        internal static byte[] HexStringToByteArray(string Hex)
        {
            byte[] Bytes = new byte[Hex.Length / 2];
            int[] HexValue = new int[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x0B, 0x0C, 0x0D,
                                 0x0E, 0x0F };

            for (int x = 0, i = 0; i < Hex.Length; i += 2, x += 1)
            {
                Bytes[x] = (byte)(HexValue[Char.ToUpper(Hex[i + 0]) - '0'] << 4 |
                                  HexValue[Char.ToUpper(Hex[i + 1]) - '0']);
            }

            return Bytes;
        }

        internal static string GetAlgorithemName(Type type)
        {
            HashAlgorithemAttribute attr = null;
            object[] attrs = type.GetCustomAttributes
                (typeof(HashAlgorithemAttribute), true);
            if (attrs.Length > 0)
            {
                attr = attrs[0] as HashAlgorithemAttribute;
            }
            if (attr != null)
            {
                return attr.Name;
            }
            else
            {
                return string.Empty;
            }
        }

        internal static Dictionary<string, Type> _algorithems = new Dictionary<string, Type>();
        internal static bool _algorithemsLoaded = false;
        internal static object _lockHandle = new object();

        internal static IHashingAlgorithem GetAlgorithem(string name)
        {
            if (!_algorithemsLoaded)
            {
                lock(_lockHandle)
                {
                    _algorithems = new Dictionary<string,Type>();
                }
                Type typHashAlgorithem = typeof(IHashingAlgorithem);
                Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
                foreach (Assembly asm in asms)
                {
                    Type[] types = asm.GetTypes();
                    foreach (Type type in types)
                    {
                        if (type.IsSubclassOf (typHashAlgorithem))
                        {
                            string algorithemName = GetAlgorithemName(type);
                            if (!string.IsNullOrEmpty( algorithemName))
                            {
                                lock (_lockHandle)
                                {
                                    _algorithems[algorithemName] = type;
                                }
                            }
                        }
                    }
                }
                _algorithemsLoaded = true;
            }

            IHashingAlgorithem ret = null;
            if ( _algorithems.ContainsKey (name))
            {
               ret = Activator.CreateInstance (_algorithems[name]) as IHashingAlgorithem;
            }

            return ret;
        }
    }
}
